package com.jeeplus.modules.api.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.alibaba.fastjson.JSONObject;
import com.jeeplus.common.config.Global;
import com.jeeplus.common.utils.net.IPUtil;

/**
 * @Description:微信支付
 * @Date: 2017-9-7 17:14
 */
public class WXPayUtil {
	private static Logger logger = LoggerFactory.getLogger(WXPayUtil.class);

	/**
	 * 微信支付
	 * 
	 * @param openid
	 *            微信id
	 * @param payMoney
	 *            金额 单位为分
	 * @param body
	 *            标题
	 * @param attach
	 *            附加数据
	 * @param orderNum
	 *            订单号
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> wxPay(String openid, String payMoney, String body, String attach, String orderNum) throws Exception {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		Map<String, String> resultObj = new HashMap<String, String>();
		try {
			// 生成的随机字符串
			String nonce_str = generateUUID();
			// 获取客户端的ip地址
			String spbill_create_ip = new IPUtil().getRemoteAddress(request);
			Map<String, String> params = new HashMap<String, String>();
			params.put("appid", Global.getConfig("wx.appId"));
			params.put("mch_id", Global.getConfig("wx.mchId"));
			params.put("nonce_str", nonce_str);
			params.put("body", body);
			params.put("out_trade_no", orderNum);// 商户订单号
			params.put("total_fee", payMoney);// 支付金额，这边需要转成字符串类型，否则后面的签名会失败
			params.put("spbill_create_ip", spbill_create_ip);
			params.put("notify_url", Global.getConfig("wx.notifyUrl"));// 支付成功后的回调地址
			params.put("trade_type", Global.getConfig("wx.tradeType"));// 支付方式
			params.put("openid", openid);
			params.put("attach", attach); // 附加数据，在查询API和支付通知中原样返回，可作为自定义参数使用。
			params.put("sign", sign(createLinkString(params), Global.getConfig("wx.paySignKey"), "utf-8").toUpperCase());
			// 拼接统一下单接口使用的xml数据，要将上一步生成的签名一起拼接进去
			String xml = mapToXml(params);
			logger.debug("调试模式_统一下单接口 请求XML数据：" + xml);
			// 调用统一下单接口，并接受返回的结果
			String result = httpRequest(Global.getConfig("wx.uniformorder"), "POST", xml);
			logger.debug("调试模式_统一下单接口 返回XML数据：" + result);
			// 将解析结果存储在HashMap中
			Map<String, String> map = doXMLParse(result);
			String return_code = map.get("return_code");// 返回状态码
			if ("SUCCESS".equals(return_code)) {
				String prepay_id = map.get("prepay_id");// 返回的预付单信息
				resultObj.put("nonceStr", nonce_str);
				resultObj.put("prepay", "prepay_id=" + prepay_id);
				long timeStamp = getCurrentTimestamp();
				resultObj.put("timeStamp", timeStamp + "");// 这边要将返回的时间戳转化成字符串，不然小程序端调用wx.requestPayment方法会报签名错误
				// 拼接签名需要的参数
				String stringSignTemp = "appId=" + Global.getConfig("wx.appId") + "&nonceStr=" + nonce_str
						+ "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" + timeStamp;
				// 再次签名，这个签名用于小程序端调用wx.requesetPayment方法
				String paySign = sign(stringSignTemp, Global.getConfig("wx.paySignKey"), "utf-8").toUpperCase();
				resultObj.put("paySign", paySign);
				resultObj.put("appId", Global.getConfig("wx.appId"));
				resultObj.put("signType", "MD5");
				resultObj.put("orderId", orderNum);
				// 返回给小程序端需要的参数
				logger.debug(resultObj.toString());
			}
		} catch (Exception e) {
			logger.error("系统异常:" + e.getMessage());
		}
		return resultObj;
	}

	/** 微信退款
     * @param out_trade_no 商户这边的订单号 
     * @param transaction_id 微信那边的交易单号 
     * @param totalFee 订单的金额 单位为分
     * @param refundFee 要退的金额 单位为分
     */  
    public static JSONObject refund(String out_trade_no, String transaction_id, String totalFee, String refundFee) {  
        try{  
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(Global.getConfig("wx.certName"));  
            try {  
                keyStore.load(instream, Global.getConfig("wx.mchId").toCharArray());  
            }finally {  
                instream.close();  
            }  
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, Global.getConfig("wx.mchId").toCharArray()).build();  
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(  
                    sslcontext, new String[] { "TLSv1" }, null,  
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
            CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();  
            HttpPost httppost = new HttpPost(Global.getConfig("wx.refundUrl"));  
            
            String nonceStr = generateUUID();
            
            SortedMap<String,String> parameters = new TreeMap<String,String>();
            parameters.put("appid", Global.getConfig("wx.appId"));
            parameters.put("mch_id", Global.getConfig("wx.mchId"));
            parameters.put("nonce_str", nonceStr);
            parameters.put("out_trade_no", out_trade_no);
            parameters.put("transaction_id", transaction_id);
            parameters.put("out_refund_no", nonceStr);
            parameters.put("fee_type", "CNY");
            parameters.put("total_fee", totalFee);
            parameters.put("refund_fee", refundFee);
            parameters.put("op_user_id", Global.getConfig("wx.mchId"));
            parameters.put("sign", createSign(parameters, Global.getConfig("wx.paySignKey")));
            String xml = sortedMapToXml(parameters);
            
            try {  
                StringEntity se = new StringEntity(xml);  
                httppost.setEntity(se);  
                CloseableHttpResponse responseEntry = httpclient.execute(httppost);  
                try {  
                    HttpEntity entity = responseEntry.getEntity();  
                    if (entity != null) {  
                        SAXReader saxReader = new SAXReader();  
                        Document document = saxReader.read(entity.getContent());  
                        Element rootElt = document.getRootElement();  
                        System.out.println("根节点：" + rootElt.getName());  
                        System.out.println("result_code==="+rootElt.elementText("result_code"));  
                        System.out.println("return_msg==="+rootElt.elementText("return_msg"));  
                        String resultCode = rootElt.elementText("result_code");  
                        JSONObject result = new JSONObject();  
                        Document documentXml = DocumentHelper.parseText(xml);  
                        Element rootEltXml = documentXml.getRootElement();  
                        if(resultCode.equals("SUCCESS")){  
                            result.put("weixinPayUrl", rootElt.elementText("code_url"));  
                            result.put("prepayId", rootElt.elementText("prepay_id"));  
                            result.put("status","success");  
                            result.put("msg","success");  
                        }else{  
                            result.put("status","false");  
                            result.put("msg",rootElt.elementText("err_code_des"));  
                        }
                        logger.debug("result:" + result.toString());
                        return result;  
                    }  
                    EntityUtils.consume(entity);  
                }  
                finally {  
                    responseEntry.close();  
                }  
            }  
            finally {  
                httpclient.close();  
            }  
            return null;  
        }catch(Exception e){  
            e.printStackTrace();  
            JSONObject result = new JSONObject();  
            result.put("status","error");  
            result.put("msg",e.getMessage());  
            return result;  
        }  
    }

	/*public static String PostRequest(String url, String data) throws IOException {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpClient client = new HttpClient();
		PostMethod post = new PostMethod(url);
		String result = "";
		post.addRequestHeader("Content-Type", "text/html; charset=utf-8");
		post.addRequestHeader("content", "text/html; charset=utf-8");
		post.setRequestBody(data);
		try {
			int status = client.executeMethod(post);
			result = post.getResponseBodyAsString();
			result = new String(result.getBytes(post.getResponseCharSet()), "utf-8");
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}*/

	/**
	 * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
	 */
	private static String createSign(SortedMap<String, String> packageParams, String AppKey) {
		StringBuilder sb = new StringBuilder();
		Set<Entry<String, String>> es = packageParams.entrySet();
		Iterator<Entry<String, String>> it = es.iterator();
		while (it.hasNext()) {
			Entry<String, String> entry = it.next();
			String k = entry.getKey();
			String v = entry.getValue();
			if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
				sb.append(k + "=" + v + "&");
			}
		}
		sb.append("key=" + AppKey);
		String sign = DigestUtils.md5Hex(getContentBytes(sb.toString(), "UTF-8")).toUpperCase();
		return sign;
	}

	/**
	 * @Author: HONGLINCHEN
	 * @Description:微信支付 统一下单
	 * @param out_trade_no
	 * @param body
	 * @param detail
	 * @param total_fee
	 * @param ip_address
	 * @Date: 2017-9-11 14:35
	 * @return:
	 */
	/*public static String unifiedOrder(String out_trade_no, String body, String detail, int total_fee,
			String ip_address) {
		StringBuilder xml = new StringBuilder();
		String data = null;
		try {
			xml.append("</xml>");
			if (body.length() > 32) {
				body = body.substring(0, 32);
			}
			SortedMap<String, String> parameters = new TreeMap();
			parameters.put("appid", Global.getConfig("wx.appId"));
			parameters.put("body", body);
			parameters.put("detail", detail);
			parameters.put("mch_id", Global.getConfig("wx.mchId"));
			parameters.put("nonce_str", generateUUID());
			parameters.put("notify_url", "http://www.aidongsports.com/wx");
			parameters.put("out_trade_no", out_trade_no);
			parameters.put("fee_type", "CNY");
			parameters.put("spbill_create_ip", ip_address);
			parameters.put("total_fee", String.valueOf(total_fee));
			parameters.put("trade_type", "APP");
			parameters.put("sign", createSign(parameters, Global.getConfig("wx.paySignKey")));
			data = PostRequest("https://api.mch.weixin.qq.com/pay/unifiedorder", sortedMapToXml(parameters));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return data;
	}*/

	/**
	 * @Author: HONGLINCHEN
	 * @Description:微信退款
	 * @param out_trade_no
	 * @param total_fee
	 * @Date: 2017-9-11 14:35
	 * @return:
	 */
	/*public static String wxPayRefund(String out_trade_no, String transaction_id, String total_fee) {
		StringBuilder xml = new StringBuilder();
		String data = null;
		try {
			String nonceStr = generateUUID();
			xml.append("</xml>");
			SortedMap<String, String> parameters = new TreeMap<String, String>();
			parameters.put("appid", Global.getConfig("wx.appId"));
			parameters.put("mch_id", Global.getConfig("wx.mchId"));
			parameters.put("nonce_str", nonceStr);
			parameters.put("out_trade_no", out_trade_no);
			parameters.put("transaction_id", transaction_id);
			parameters.put("out_refund_no", nonceStr);
			parameters.put("fee_type", "CNY");
			parameters.put("total_fee", total_fee);
			parameters.put("refund_fee", total_fee);
			parameters.put("op_user_id", Global.getConfig("wx.mchId"));
			parameters.put("sign", createSign(parameters, Global.getConfig("wx.paySignKey")));
			data = sortedMapToXml(parameters);
		} catch (Exception e) {
			System.err.println(e.getMessage());
			return null;
		}
		return data;
	}
*/
	/**
	 * 证书使用 微信退款
	 */
	/*public static String wxPayBack(String url, String data) throws Exception {
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		FileInputStream instream = new FileInputStream(new File("D:\\微信商户平台支付证书\\apiclient_cert.p12"));
		String result = "";
		try {
			keyStore.load(instream, Global.getConfig("wx.mchId").toCharArray());
		} finally {
			instream.close();
		}

		// Trust own CA and all self-signed certs
		SSLContext sslcontext = SSLContexts.custom()
				.loadKeyMaterial(keyStore, Global.getConfig("wx.mchId").toCharArray()).build();
		// Allow TLSv1 protocol only
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
		try {
			HttpPost httppost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
			StringEntity entitys = new StringEntity(data);
			httppost.setEntity((HttpEntity) entitys);
			CloseableHttpResponse response = httpclient.execute(httppost);
			try {
				HttpEntity entity = response.getEntity();

				if (entity != null) {
					BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
					String text = "";
					String t = "";
					while ((text = bufferedReader.readLine()) != null) {
						t += text;
					}
					byte[] temp = t.getBytes("gbk");// 这里写原编码方式
					String newStr = new String(temp, "utf-8");// 这里写转换后的编码方式
					result = newStr;
				}
				EntityUtils.consume(entity);
			} finally {
				response.close();
			}
		} finally {
			httpclient.close();
		}
		return result;
	}
*/
	/**
	 * XML格式字符串转换为Map 微信支付 解析xml xml转map 获取prepay_id
	 * 
	 * @param strXML
	 *            XML字符串
	 * @return XML数据转换后的Map
	 * @throws Exception
	 */
	private static Map<String, String> xmlToMap(String strXML) throws Exception {
		try {
			Map<String, String> data = new HashMap<String, String>();
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
			InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
			org.w3c.dom.Document doc = documentBuilder.parse(stream);
			doc.getDocumentElement().normalize();
			NodeList nodeList = doc.getDocumentElement().getChildNodes();
			for (int idx = 0; idx < nodeList.getLength(); ++idx) {
				Node node = nodeList.item(idx);
				if (node.getNodeType() == Node.ELEMENT_NODE) {
					org.w3c.dom.Element element = (org.w3c.dom.Element) node;
					data.put(element.getNodeName(), element.getTextContent());
				}
			}
			try {
				stream.close();
			} catch (Exception ex) {
				// do nothing
			}
			return data;
		} catch (Exception ex) {
			logger.error("Invalid XML, can not convert to map. Error message: {}. XML content: {}",	ex.getMessage(), strXML);
			throw ex;
		}
	}

	/**
	 * 生成 MD5
	 *
	 * @param data
	 *            待处理数据
	 * @return MD5结果
	 */
	private static String MD5(String data) throws Exception {
		MessageDigest md = MessageDigest.getInstance("MD5");
		byte[] array = md.digest(data.getBytes("UTF-8"));
		StringBuilder sb = new StringBuilder();
		for (byte item : array) {
			sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
		}
		return sb.toString().toUpperCase();
	}

	/**   
     * 签名字符串   
     * @param text需要签名的字符串   
     * @param key 密钥   
     * @param input_charset编码格式   
     * @return 签名结果   
     */     
	private static String sign(String text, String key, String input_charset) {     
        text = text + "&key=" + key;     
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));     
    } 
    
    /**   
     * @param content   
     * @param charset   
     * @return   
     * @throws SignatureException   
     * @throws UnsupportedEncodingException   
     */     
    private static byte[] getContentBytes(String content, String charset) {     
        if (charset == null || "".equals(charset)) {     
            return content.getBytes();     
        }     
        try {     
            return content.getBytes(charset);     
        } catch (UnsupportedEncodingException e) {     
            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);     
        }     
    }  
	/**
	 * 生成 HMACSHA256
	 * 
	 * @param data
	 *            待处理数据
	 * @param key
	 *            密钥
	 * @return 加密结果
	 * @throws Exception
	 */
    private static String HMACSHA256(String data, String key) throws Exception {
		Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
		SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
		sha256_HMAC.init(secret_key);
		byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
		StringBuilder sb = new StringBuilder();
		for (byte item : array) {
			sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
		}
		return sb.toString().toUpperCase();
	}

	/**
	 * @Description:请求值转换为xml格式 SortedMap转xml
	 * @param params
	 */
	private static String sortedMapToXml(SortedMap<String, String> params) {
		StringBuilder sb = new StringBuilder();
		Set<Entry<String, String>> es = params.entrySet();
		Iterator<Entry<String, String>> it = es.iterator();
		sb.append("<xml>\n");
		while (it.hasNext()) {
			Entry<String, String> entry = it.next();
			String k = entry.getKey();
			String v = entry.getValue();
			sb.append("<" + k + ">");
			sb.append(v);
			sb.append("</" + k + ">\n");
		}
		sb.append("</xml>");
		return sb.toString();
	}

	 /**   
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串   
     * @param params 需要排序并参与字符拼接的参数组   
     * @return 拼接后字符串   
     */     
	private static String createLinkString(Map<String, String> params) {     
        List<String> keys = new ArrayList<String>(params.keySet());     
        Collections.sort(keys);     
        String prestr = "";     
        for (int i = 0; i < keys.size(); i++) {     
            String key = keys.get(i);     
            String value = params.get(key);     
            if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符     
                prestr = prestr + key + "=" + value;     
            } else {     
                prestr = prestr + key + "=" + value + "&";     
            }     
        }     
        return prestr;     
    }
    
	/**
	 * @Description:请求值转换为xml格式 Map转xml
	 * @param params
	 */
	private static String mapToXml(Map<String, String> params) {
		StringBuilder sb = new StringBuilder();
		Set<Entry<String, String>> es = params.entrySet();
		Iterator<Entry<String, String>> it = es.iterator();
		sb.append("<xml>\n");
		while (it.hasNext()) {
			Entry<String, String> entry = it.next();
			String k = entry.getKey();
			String v = entry.getValue();
			sb.append("<" + k + ">");
			sb.append(v);
			sb.append("</" + k + ">\n");
		}
		sb.append("</xml>");
		return sb.toString();
	}

	 /**   
     *   
     * @param requestUrl请求地址   
     * @param requestMethod请求方法   
     * @param outputStr参数   
     */     
	private static String httpRequest(String requestUrl,String requestMethod,String outputStr){     
        // 创建SSLContext     
        StringBuilder buffer = null;     
        try{     
            URL url = new URL(requestUrl);     
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();     
            conn.setRequestMethod(requestMethod);     
            conn.setDoOutput(true);     
            conn.setDoInput(true);     
            conn.connect();     
            //往服务器端写内容     
            if(null !=outputStr){     
                OutputStream os=conn.getOutputStream();     
                os.write(outputStr.getBytes("utf-8"));     
                os.close();     
            }     
            // 读取服务器端返回的内容     
            InputStream is = conn.getInputStream();     
            InputStreamReader isr = new InputStreamReader(is, "utf-8");     
            BufferedReader br = new BufferedReader(isr);     
            buffer = new StringBuilder();     
            String line = null;     
            while ((line = br.readLine()) != null) {     
                buffer.append(line);     
            }
            br.close();  
        }catch(Exception e){     
            e.printStackTrace();     
        }  
        return buffer.toString();  
    }   
    
    /** 
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。 
     * @param strxml 
     * @return 
     * @throws JDOMException 
     * @throws IOException 
     */  
    private static Map<String, String> doXMLParse(String strxml) throws Exception {  
        if(null == strxml || "".equals(strxml)) {  
            return null;  
        }  
          
        Map<String, String> m = new HashMap<String, String>();  
        InputStream in = String2Inputstream(strxml);  
        SAXReader builder = new SAXReader();
        builder.setEncoding("UTF-8");
        Document doc = builder.read(in);  
        Element root = doc.getRootElement(); 
        List list = root.elements();
        Iterator it = list.iterator();  
        while(it.hasNext()) {  
            Element e = (Element) it.next();  
            String k = e.getName();  
            String v = "";  
            List children = e.elements();
            if(children.isEmpty()) {  
                v = e.getTextTrim();
            } else {  
                v = getChildrenText(children);  
            }  
            m.put(k, v);  
        }  
        //关闭流  
        in.close();  
          
        return m;  
    }
    
    /** 
     * 获取子结点的xml 
     * @param children 
     * @return String 
     */  
    private static String getChildrenText(List children) {  
        StringBuilder sb = new StringBuilder();  
        if(!children.isEmpty()) {  
            Iterator it = children.iterator();  
            while(it.hasNext()) {  
                Element e = (Element) it.next();  
                String name = e.getName();  
                String value = e.getTextTrim();
                List list = e.elements();
                sb.append("<" + name + ">");  
                if(!list.isEmpty()) {  
                    sb.append(getChildrenText(list));  
                }  
                sb.append(value);  
                sb.append("</" + name + ">");  
            }  
        }  
        return sb.toString();  
    }  
    
    private static InputStream String2Inputstream(String str) throws IOException {  
    	return IOUtils.toInputStream(str, StandardCharsets.UTF_8.name());
    }
    
	/**
	 * 获取当前时间戳，单位秒
	 * 
	 * @return
	 */
	private static long getCurrentTimestamp() {
		return System.currentTimeMillis() / 1000;
	}

	/**
	 * 生成 uuid， 即用来标识一笔单，也用做 nonce_str
	 * 
	 * @return
	 */
	private static String generateUUID() {
		return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
	}
}
